package com.learn.mybatis.dao;

import java.util.Properties;

import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;

/**
 * @Signature: 完成插件（Interceptor拦截器）签名：告诉MyBatis当前插件用来拦截哪个对象的哪个方法
 * 	type：要拦截四大对象中的哪一个
 * 	method: 要拦截对象中的那个方法
 * 	args: 指定被拦截方法的参数列表，（因有的方法可能有重载方法，同名方法间参数数量不一，所以要特殊指定参数来锁定到底是哪一个方法。）
 *
 * 	StatementHandler 用于处理sql预编译
 * 	    parameterize 是参数预编译方法
 */
@Intercepts(
        {
                @Signature(type = StatementHandler.class, method = "parameterize", args = java.sql.Statement.class)
        })
public class MyFirstPlugin implements Interceptor {

    /**
     * intercept：拦截目标对象的目标方法的执行
     * 只有在处理指定的要拦截的目标对象的目标方法时才会进到这里。
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("MyFirstPlugin拦截器--intercept方法--拦截目标方法:"+invocation.getMethod());
        // ... 执行目标方法前，做一些事情

        // 放行被拦截器管制的目标方法
        Object proceed = invocation.proceed();

        // ... 执行目标方法后，做一些事情


        // 返回执行后的返回值
        return proceed;
    }

    /**
     * plugin：用来包装目标对象，为目标对象创建一个代理对象
     * 该方法会在四大对象创建时调用。即使四大对象没有被插件声明管制，也会调用。
     */
    @Override
    public Object plugin(Object target) {
        System.out.println("MyFirstPlugin拦截器--plugin方法--开始包装目标对象："+target);
    	// 手动创建代理对象 Proxy.newProxyInstance
        // 但mybatis提供了方便创建代理对象的方法，用Plugin的wrap方法，帮助我们生成代理对象。
        // Plugin的wrap方法，只会在当前处理的对象，是被声明要拦截的对象时，才会创建它的代理对象。否则返回原对象，不作拦截处理。
        Object wrap = Plugin.wrap(target, this);
        // 返回为当前target创建的动态代理对象
        return wrap;
    }

    /**
     * setProperties：用于在插件注册时，设置插件的property属性。
     */
    @Override
    public void setProperties(Properties properties) {
        System.out.println("给插件MyFirstPlugin（Interceptor拦截器）配置的信息：" + properties);
    }

}
